//
// Created by 86131 on 2020/12/19.
//
#include <iostream>
#include <vector>
using namespace std;

int everyStep(int step, vector<vector<vector<char>>>& board);  //每一步棋执行的函数
bool breathlessOrNot(vector<vector<vector<char>>>& board, vector<vector<char>>& flag, int step, int i, int j); //判断该子是否无气
void setAlive(vector<vector<vector<char>>>& board, vector<vector<char>>& flag, int step, int i, int j);  //盘活该子以及所有相连同色子

int main()
{
//三维数组记录每步的棋盘情况，棋盘的0行、列和20行、列不用，只是为了方便避免数组越界
    vector<vector<vector<char>>> board(1000, vector<vector<char>>(21, vector<char>(21, '+')));
    for (int i = 1; i <= 19; i++)  //每次测试最终输入棋盘局面
    {
        for (int j = 1; j <= 19; j++)
            cout << board[1][i][j];
        cout << endl;
    }
    int n=0;
    for (int step = 0; step < 1000; step++,n++) { //每一步棋执行的函数
        int flag1 = everyStep(step, board);
        if(flag1==-1)break;
    }

    for (int i = 1; i <= 19; i++)  //每次测试最终输入棋盘局面
        {
        for (int j = 1; j <= 19; j++)
            cout << board[n - 1][i][j];
        cout << endl;
    }
    return 0;
}

//每一步棋执行的函数
int everyStep(int step, vector<vector<vector<char>>>& board)
{
    //如果不是第一步(step!=0)，先移植上一步的棋盘局面
    if (step)
        board[step] = board[step - 1];
    int colorInput;
    int rowInput, columnInput;
    cin >> colorInput >> rowInput >> columnInput;
    //cin.get();
    if(colorInput==0&&rowInput==0&&columnInput==0)
        return -1;

//判断落子处是否无子
    if (board[step][rowInput][columnInput] == '+') {
        if (colorInput == 1)
            board[step][rowInput][columnInput] = 'o';  //先落
        if(colorInput==2)
            board[step][rowInput][columnInput] = '#';
    }
    char enemyColor;
    if (colorInput == 1)
        enemyColor = '#';
    else
        enemyColor = 'o';
    vector<vector<char>> flag(21, vector<char>(21, 0)); //每一步的棋局都新建一个char型辅助二维数组来标记棋子是否有气（0表示未访问，1表示无气，2表示有气）

    int enemyBreathless = 0; //是否有相邻敌子无气，值不是0则表示落子之后有敌子无气（但值并不是无气的敌子的数量）
    bool thisBreathless = breathlessOrNot(board, flag, step, rowInput, columnInput); //判断该步落子是否无气

    //判断周围敌子是否无气
    for (int rowNextTo = rowInput - 1; rowNextTo <= rowInput + 1; rowNextTo += 2) //判断上下相邻的棋子
        if (board[step][rowNextTo][columnInput] == enemyColor && flag[rowNextTo][columnInput] == 0) //相邻棋子是敌子且未被访问
            if (breathlessOrNot(board, flag, step, rowNextTo, columnInput))
                enemyBreathless++;

    for (int colomnNextTo = columnInput - 1; colomnNextTo <= columnInput + 1; colomnNextTo += 2) //判断左右相邻的棋子
        if (board[step][rowInput][colomnNextTo] == enemyColor && flag[rowInput][colomnNextTo] == 0)
            if (breathlessOrNot(board, flag, step, rowInput, colomnNextTo))
                enemyBreathless++;

    //判断是否违反规则6：如果某方在此下子，会使该子立即呈无气状态，同时又不能提取对方的棋子，这个点叫做“禁着点”，该方不能在此下子。
    if (thisBreathless && !enemyBreathless)
    {
        //cout << "miss 2" << endl;
        board[step] = board[step - 1];  //棋局恢复到上一步
        return 0;
    }
    else if (enemyBreathless)  //如果敌子无气，则进行提子
    {
        for (int i = 1; i <= 19; i++)
            for (int j = 1; j <= 19; j++)
                if (board[step][i][j] == enemyColor && flag[i][j] == 1)
                    board[step][i][j] = '+';
    }

    //判断是否违反规则7：禁止全局同形：无论哪一方，在成功进行了着子、提子操作后，棋盘局面不能和任何之前的局面相同。
    for (int preStep = step - 1; preStep >= 0; preStep--)
        if (board[step] == board[preStep])
        {
            //cout << "miss 3" << endl;
            board[step] = board[step - 1];  //棋局恢复到上一步
            return 0;
        }
    return 1;
}

//判断该子是否无气
bool breathlessOrNot(vector<vector<vector<char>>>& board, vector<vector<char>>& flag, int step, int i, int j)
{
    char thisColor = board[step][i][j];
    if ((board[step][i - 1][j] == '+' && i - 1 >= 1) || (board[step][i + 1][j] == '+' && i + 1 <= 19) || (board[step][i][j - 1] == '+' && j - 1 >= 1) || (board[step][i][j + 1] == '+' && j + 1 <= 19))
    {   //如果该子四周有气，则该子及其所有“相连”同色子都有气（flag置为2），同时return false；
        setAlive(board, flag, step, i, j); //该子为第一个被发现有气的子，将该子及其所有相连同色子flag置为2，表示有气
        return false;
    }

    flag[i][j] = 1;  //该子四周无气，先假设其无气（后面可能会被重新置为2）

    for (int rowNextTo = i - 1; rowNextTo <= i + 1; rowNextTo += 2)  //判断上下相邻位置的同色子
        if (board[step][rowNextTo][j] == thisColor && flag[rowNextTo][j] == 0)  //同色子要未被访问才执行后续判断
            if (!breathlessOrNot(board, flag, step, rowNextTo, j))
                return false;
    for (int colomnNextTo = j - 1; colomnNextTo <= j + 1; colomnNextTo += 2) //判断左右相邻位置的同色子
        if (board[step][i][colomnNextTo] == thisColor && flag[i][colomnNextTo] == 0)
            if (!breathlessOrNot(board, flag, step, i, colomnNextTo))
                return false;

    return true;
}
//盘活该子以及所有相连同色子
void setAlive(vector<vector<vector<char>>>& board, vector<vector<char>>& flag, int step, int i, int j)
{
    char thisColor = board[step][i][j];
    flag[i][j] = 2;
    for (int row = i - 1; row <= i + 1; row += 2)  //判断上下相邻位置
        if (board[step][row][j] == thisColor && flag[row][j] != 2)
            setAlive(board, flag, step, row, j);

    for (int column = j - 1; column <= j + 1; column += 2) //判断左右相邻位置
        if (board[step][i][column] == thisColor && flag[i][column] != 2)
            setAlive(board, flag, step, i, column);
}
